{smcl}
{* 16may2014}{...}
{cmd:help mata mm_finvert()}
{hline}

{title:Title}

{p 4 19 2}
{bf:mm_finvert() -- Numerical inversion of univariate function}


{title:Syntax}

{p 8 21 2}{it:real vector} {cmd:mm_finvert(}{it:y}{cmd:,} {it:f}{cmd:,}
{it:df} [{cmd:,} {it:x0}{cmd:,} {it:tol}{cmd:,} {it:itr}{cmd:,} {it:opt}]{cmd:)}

{p 8 21 2}{it:real vector} {cmd:mm_finvert(}{it:y}{cmd:,} {it:f}{cmd:,}
{it:lo}{cmd:,} {it:up} [{cmd:,} {it:tol}{cmd:,} {it:itr}{cmd:,} {it:opt}]{cmd:)}

{pstd}
where


{p 12 16 2}
{it:y}:  {it:real vector} containing the values for which function
{it:f} be inverted

{p 12 16 2}
{it:f}:  {it:pointer scalar} containing address of function to be
inverted; usually
this is coded {cmd:&}{it:funcname}{cmd:()}

{p 11 16 2}
{it:df}:  {it:pointer scalar} containing address of function providing
first derivative of function {it:f} (Newton-Raphson method only)

{p 11 16 2}
{it:x0}:  {it:real vector} containing initial guess
(Newton-Raphson method only); if {it:x0} omitted, {it:y} is used as initial
guess

{p 11 16 2}
{it:lo}:  {it:real vector} containing lower endpoint of the search
interval (Brent's method only)

{p 11 16 2}
{it:up}:  {it:real vector} containing upper endpoint of the search
interval (Brent's method only)

{p 10 16 2}
{it:tol}:  {it:real scalar} specifying acceptable tolerance for the
estimate (default is {it:tol}=0 to find the solution as
accurate as possible)

{p 10 16 2}
{it:itr}:  {it:real scalar} specifying the maximum number of
iterations (default is {it:itr}=1000)

{p 10 16 2}
{it:opt}:  optional argument to pass on to {it:f} and {it:df}


{title:Description}

{pstd}{cmd:mm_finvert()} numerically inverts function {it:f} for the
outcomes {it:y}, that is, {cmd:mm_finvert()} returns an approximation
for {it:x} given {it:y}, where
{it:y} = {it:f}{cmd:(}{it:x}{cmd:)}.

{pstd}Two methods are available:

{phang2}{cmd:mm_finvert(}{it:y}{cmd:,} {it:f}{cmd:,}
{it:df} [{cmd:,} {it:x0}{cmd:,} {it:...}]{cmd:)}: If function {it:df}, providing the
first derivative of {it:f} is given, then the Newton-Raphson method
implemented in {helpb mf_mm_nrroot:mm_nrroot()} is applied. {it:x0} may
be used to specify an initial guess for {it:x}. Specify {it:x0} as a
scalar to use the same initial guess for {it:x}
with all outcomes in {it:y}. If {it:x0} is omitted, {it:y} is used as the initial guess.

{phang2}{cmd:mm_finvert(}{it:y}{cmd:,} {it:f}{cmd:,}
{it:lo}{cmd:,} {it:up} [{cmd:,} {it:...}]{cmd:)}: If derivatives are
not provided, Brent's method implemented in {helpb mf_mm_root:mm_root()}
is applied. With this method, {it:lo} and {it:up}, the lower and and
upper endpoints of the search interval, have to be specified. Specify
{it:lo} and {it:up} as scalars to use the same search interval for
{it:x} with all outcomes in {it:y}.

{pstd}With both methods, {it:tol} sets the acceptable tolerance for the accuracy
of the approximation of {it:x}. See help for {helpb mf_mm_nrroot:mm_nrroot()}
and {helpb mf_mm_root:mm_root()} for details. Furthermore, {it:itr} sets the maximum number of
iterations. {cmd:mm_finvert()} aborts with error, if convergence is
not reach within {it:itr} iterations for any element in {it:y}. 

{pstd} Optional argument {it:opt} can be used to pass on information to
function {it:f}. {it:opt} can contain anything, including pointers to other Mata
objects.

{pstd}{cmd:mm_finvert()} is loosely based on suggestions made by Jeff
Pitblado on Statalist (see
{browse "http://statacorp.com/statalist/archive/2005-09/msg00837.html"}).


{title:Remarks}

{pstd}{cmd:mm_finvert()} may be useful, for example, to generate random draws
from a given distribution function. If the first derivative of the distribution
function, i.e. the density function, is known, the approximation of the
inversion can be computed using the Newton-Raphson method. For example,
normally distributed random data could be produced as follows:

        {com}: function fx(x) return(normal(x))

        : function dfx(x) return(normalden(x))

        : y = uniform(5,1)
        {res}
        {com}: mm_finvert(y, &fx(), &dfx())
        {res}       {txt}          1
            {c TLC}{hline 15}{c TRC}
          1 {c |}  {res}1.935200359{txt}  {c |}
          2 {c |}  {res}1.270466906{txt}  {c |}
          3 {c |}  {res}1.423621095{txt}  {c |}
          4 {c |}  {res}-.516603887{txt}  {c |}
          5 {c |}  {res}1.213896688{txt}  {c |}
            {c BLC}{hline 15}{c BRC}

{pstd}If a function providing the first derivative is not available,
the inversion can be computed using Brent's zero finding method.
Brent's method works very well in a variety of contexts. However, it
is usually slower than the Newton-Raphson method and it requires the
user to specify a range within which the solution is to be sought
for. Example:

        {com}: mm_finvert(y, &fx(),-5, 5)
        {res}       {txt}          1
            {c TLC}{hline 15}{c TRC}
          1 {c |}  {res}1.935200359{txt}  {c |}
          2 {c |}  {res}1.270466906{txt}  {c |}
          3 {c |}  {res}1.423621095{txt}  {c |}
          4 {c |}  {res}-.516603887{txt}  {c |}
          5 {c |}  {res}1.213896688{txt}  {c |}
            {c BLC}{hline 15}{c BRC}

{pstd}The above examples have only illustrative purpose. More
accurate and much more efficient would be to use the built-in function
{cmd:invnormal()} in this context (see help for
{helpb mf_normal:normal()}), that is:

        {com}: invnormal(y)
        {res}       {txt}          1
            {c TLC}{hline 15}{c TRC}
          1 {c |}  {res}1.935200359{txt}  {c |}
          2 {c |}  {res}1.270466906{txt}  {c |}
          3 {c |}  {res}1.423621095{txt}  {c |}
          4 {c |}  {res}-.516603887{txt}  {c |}
          5 {c |}  {res}1.213896688{txt}  {c |}
            {c BLC}{hline 15}{c BRC}

{pstd}Use {it:opt} to pass on arguments to the function to be inverted. Here is 
an example where {it:opt} is a vector containing two parameters, mean and 
standard deviation:

        {com}: function fx1(x, opt) return(normal((x-opt[1])/opt[2]))

        : function dfx1(x, opt) return(normalden((x-opt[1])/opt[2]))

        : mm_finvert(y, &fx1(), &dfx1(), y, 0, 1000, (1, 2))
        {res}       {txt}          1
            {c TLC}{hline 15}{c TRC}
          1 {c |}  {res}4.870400719{txt}  {c |}
          2 {c |}  {res}3.540933812{txt}  {c |}
          3 {c |}  {res} 3.84724219{txt}  {c |}
          4 {c |}  {res}-.033207774{txt}  {c |}
          5 {c |}  {res}3.427793375{txt}  {c |}
            {c BLC}{hline 15}{c BRC}

        {com}: mm_finvert(y, &fx1(),-10, 10, 0, 1000, (1, 2))
        {res}       {txt}          1
            {c TLC}{hline 15}{c TRC}
          1 {c |}  {res}4.870400719{txt}  {c |}
          2 {c |}  {res}3.540933812{txt}  {c |}
          3 {c |}  {res} 3.84724219{txt}  {c |}
          4 {c |}  {res}-.033207774{txt}  {c |}
          5 {c |}  {res}3.427793375{txt}  {c |}
            {c BLC}{hline 15}{c BRC}

{pstd}Here is an example where {it:opt} contains pointers:

        {com}: function fx2(x, opt) return(normal((x-(*opt[1]))/(*opt[2])))

        : function dfx2(x, opt) return(normalden((x-(*opt[1]))/(*opt[2])))

        : m = 1
        {res}
        {com}: s = 2
        {res}
        {com}: mm_finvert(y, &fx2(), &dfx2(), y, 0, 1000, (&m, &s))
        {res}       {txt}          1
            {c TLC}{hline 15}{c TRC}
          1 {c |}  {res}4.870400719{txt}  {c |}
          2 {c |}  {res}3.540933812{txt}  {c |}
          3 {c |}  {res} 3.84724219{txt}  {c |}
          4 {c |}  {res}-.033207774{txt}  {c |}
          5 {c |}  {res}3.427793375{txt}  {c |}
            {c BLC}{hline 15}{c BRC}

        {com}: mm_finvert(y, &fx2(),-10, 10, 0, 1000, (&m, &s))
        {res}       {txt}          1
            {c TLC}{hline 15}{c TRC}
          1 {c |}  {res}4.870400719{txt}  {c |}
          2 {c |}  {res}3.540933812{txt}  {c |}
          3 {c |}  {res} 3.84724219{txt}  {c |}
          4 {c |}  {res}-.033207774{txt}  {c |}
          5 {c |}  {res}3.427793375{txt}  {c |}
            {c BLC}{hline 15}{c BRC}


{title:Conformability}

{pstd}
{cmd:mm_finvert(}{it:y}{cmd:,} {it:f}{cmd:,} {it:df}{cmd:,} {it:x0}{cmd:,}
{it:tol}{cmd:,} {it:itr}{cmd:,} {it:opt}{cmd:)}:{p_end}
           {it:y}:  {it:n x} 1 or 1 {it:x n}
           {it:f}:  1 {it:x} 1
          {it:df}:  1 {it:x} 1
          {it:x0}:  {it:n x} 1 or 1 {it:x n} or 1 {it:x} 1
         {it:tol}:  1 {it:x} 1
         {it:itr}:  1 {it:x} 1
         {it:opt}:  {it:r x c}
      {it:result}:  {it:n x} 1 or 1 {it:x n}

{pstd}
{cmd:mm_finvert(}{it:y}{cmd:,} {it:f}{cmd:,} {it:lo}{cmd:,} {it:up}{cmd:,}
{it:tol}{cmd:,} {it:itr}{cmd:,} {it:opt}{cmd:)}:{p_end}
           {it:y}:  {it:n x} 1 or 1 {it:x n}
           {it:f}:  1 {it:x} 1
          {it:lo}:  {it:n x} 1 or 1 {it:x n} or 1 {it:x} 1
          {it:up}:  {it:n x} 1 or 1 {it:x n} or 1 {it:x} 1
         {it:tol}:  1 {it:x} 1
         {it:itr}:  1 {it:x} 1
         {it:opt}:  {it:r x c}
      {it:result}:  {it:n x} 1 or 1 {it:x n}


{title:Diagnostics}

{pstd}None.


{title:Source code}

{pstd}
{help moremata_source##mm_finvert:mm_finvert.mata}


{title:Author}

{pstd} Ben Jann, University of Bern, jann@soz.unibe.ch


{title:Also see}

{psee}
Online:  help for
{bf:{help mf_mm_root:mm_root()}},
{bf:{help mf_mm_nrroot:mm_nrroot()}},
{bf:{help m2_ftof:[M-2] ftof}},
{bf:{help moremata}}
